<?php
/**
 * User: YL
 * Date: 2019/08/03
 */

namespace restful\commands;

use restful\utils\Helper;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use Throwable;

class GenModel extends Command
{
    /**
     * @var string
     */
    protected $path;

    protected function configure()
    {
        $this->setName('gen-model')
            ->addOption('db', 'd', Option::VALUE_OPTIONAL, 'The generated database name')
            ->addOption('table', 't', Option::VALUE_OPTIONAL, 'Exclude table names, multiple use `,` separated')
            ->addOption('prefix', 'p', Option::VALUE_OPTIONAL, 'Datatable prefixes, which are not prefixed when generating models')
            ->addOption('force', 'f', Option::VALUE_NONE, 'Whether to overwrite an existing file')
            ->addOption('clear', 'c', Option::VALUE_NONE, 'Clear all model files')
            ->addOption('author', 'a', Option::VALUE_OPTIONAL, 'Author\'s name')
            ->setDescription('Generate the model file');
    }

    protected function execute(Input $input, Output $output)
    {
        $this->path = $this->app->getAppPath() . 'common/model/';
        if ($input->hasOption('clear')) {
            $this->clearAll($output);
            $output->writeln('<info>Succeed!</info>');
            return true;
        }

        if ($input->hasOption('db')) {
            $database = $input->getOption('db');
        } else {
            $database = $this->app->db->getConnection()->getConfig('database');
        }

        $excludeTables = [];
        if ($input->hasOption('table')) {
            $excludeTables = explode(',', $input->getOption('table'));
        }

        if ($input->hasOption('prefix')) {
            $prefix = $input->getOption('prefix');
        } else {
            $prefix = $this->app->db->getConnection()->getConfig('prefix');
        }

        $force = $input->hasOption('force');
        $author = $input->hasOption('author') ? $input->getOption('author') : 'YL';

        try {
            $tables = $this->app->db->getConnection()->getTables($database);
            foreach ($tables as $table) {
                if (in_array($table, $excludeTables)) {
                    continue;
                }
                $this->buildModel($author, $table, $prefix, $force, $output);
            }
            $output->writeln('<info>Succeed!</info>');
        } catch (Throwable $e) {
            $output->writeln('<error>' . $e->getMessage() . PHP_EOL . $e->getTraceAsString() . '</error>');
        }

        return true;
    }

    /**
     * 清除所有模型
     * @param Output $output
     */
    protected function clearAll(Output $output)
    {
        $files = glob($this->path . '*.php');
        foreach ($files as $file) {
            if (basename($file) == 'Base.php') {
                continue;
            }

            unlink($file);
            $output->writeln($file . ' delete Succeed!');
        }
    }

    /**
     * 生成模型文件
     * @param string $author
     * @param string $table
     * @param string $prefix
     * @param bool $force
     * @param Output $output
     * @return bool
     */
    protected function buildModel(
        string $author,
        string $table,
        string $prefix,
        bool $force,
        Output $output
    )
    {
        $name = Helper::studly(str_replace($prefix, '', $table));
        $filePath = $this->path . $name . '.php';

        if (file_exists($filePath) && !$force) {
            clearstatcache();
            return false;
        }

        $content = $this->getBuildContent($author, $name);
        file_put_contents($filePath, $content);

        $output->writeln($filePath . ' create Succeed!');
        return true;
    }

    /**
     * 获取生成内容
     * @param string $author
     * @param string $name
     * @return string
     */
    protected function getBuildContent(string $author, string $name)
    {
        $str = <<< EOF
<?php
/**
 * User: %s
 * Date: %s
 */

namespace app\common\model;

class %s extends Base
{}
EOF;
        return sprintf($str, $author, date('Y/m/d'), $name);
    }
}